home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gekkan Dennou Club 147
/
Gekkan Dennou Club - 2000.8 Vol. 147 (Japan).7z
/
Gekkan Dennou Club - 2000.8 Vol. 147 (Japan) (Track 1).bin
/
games
/
ippon
/
source.lzh
/
enemy.c
< prev
next >
Wrap
C/C++ Source or Header
|
2000-07-07
|
6KB
|
271 lines
/* enemy.c */
#include <stdio.h>
#include <xsp2lib.h>
#include "main.h"
#include "player.h"
#include "enemy.h"
#include "shot.h"
#include "psearch.h"
#define ENEMY_MAX 32 /* 敵最大数 */
static ENEMY enemy[ENEMY_MAX]; /* ワーク */
static ENEMY *enemy_top, /* 使用中のワークのリスト */
*enemy_null_top, /* 空のワークのリスト */
*enemy_end; /* 使用中ワークのリストの末尾 */
/* 初期化関数へのポインタの配列 */
typedef void (*enemy_alloc) (ENEMY *);
enemy_alloc EnemyAllocFunc[] =
{
EnemyAllocZakoA,
EnemyAllocZakoB,
EnemyAllocCoverN,
EnemyAllocOplaser,
EnemyAllocRound4,
EnemyAllocCoverF,
EnemyAllocSword,
EnemyAllocSearchZ,
EnemyAllocSearchZ2,
EnemyAllocZako031,
EnemyAllocLBoss01,
EnemyAllocLBoss01C,
};
#define wabs(x) ((x) >= 0 ? (short) (x) : (short) -(x))
#define abs(x) ((x) >= 0 ? (int) (x) : (int) -(x))
/* ゲーム開始時に呼ばれる */
void EnemyInit (void)
{
int i;
/* リストをつなげる */
enemy_top = NULL;
enemy_end = NULL;
enemy_null_top = enemy;
for (i = 0; i < ENEMY_MAX; i++)
enemy[i].next = &enemy[i + 1];
enemy[ENEMY_MAX - 1].next = NULL;
}
/* 敵出現時に呼ばれる */
ENEMY *EnemyAlloc (short type, signed short x, signed short y)
{
ENEMY *p;
if (enemy_null_top == NULL)
return (NULL); /* 空きのワークがない(キャラクターオーバー) */
/* リストの末尾に新しいノードを追加(他とは違うので注意) */
p = enemy_null_top;
enemy_null_top = p->next;
if (enemy_top == NULL)
enemy_top = p;
else
enemy_end->next = p;
p->next = NULL;
enemy_end = p;
p->type = type;
p->lx = x << 16;
p->ly = y << 16;
p->shot = NULL;
/* 関数へのポインタを使って分岐 */
/* type が 0 なら EnemyAllocA() が、1 なら EnemyAllocB() が実行される */
EnemyAllocFunc[p->type] (p);
return (p);
}
/* 垂直同期ごとに呼ばれる */
void EnemyMove (void)
{
ENEMY *p, *q;
signed short pl_x = player->x, pl_y = player->y;
#ifdef DEBUG
enemy_sum = 0;
#endif
p = enemy_top; /* 現在注目しているワーク */
q = NULL; /* 1つ前のワーク(ワーク削除時に必要) */
while (p != NULL) {
/* 敵キャラの移動ルーチン */
#ifdef DEBUG
enemy_sum++;
#endif
/* 関数へのポインタを使って分岐 */
/* (FuncEnemy/ 以下の FuncMoveXXX() を呼んでいる) */
if ((p->func_enemy_move) (p)) { /* 返り値が非0なら消去 */
(p->func_enemy_free) (p); /* 消去関数を呼ぶ */
if (q == NULL) { /* リストの一番最初を削除 */
enemy_top = p->next;
p->next = enemy_null_top;
enemy_null_top = p;
q = NULL;
p = enemy_top;
} else {
if (p == enemy_end) { /* リストの一番最後を削除 */
q->next = NULL;
enemy_end = q;
p->next = enemy_null_top;
enemy_null_top = p;
p = q->next;
} else {
q->next = p->next;
p->next = enemy_null_top;
enemy_null_top = p;
p = q->next;
}
}
} else {
/* 敵キャラを消去しない場合 */
SHOT *p2 = shot; /* 現在注目しているショットのワーク */
signed short t;
/* プレイヤーとの当たり判定 */
if (((t = p->x + p->hit_sx) > pl_x)
&& ((t -= (short) (p->hit_sx << 1)) < pl_x)
&& ((t = p->y + p->hit_sy) > pl_y)
&& ((t -= (short) (p->hit_sy << 1)) < pl_y)) {
/* 当たった */
if ((player->status == PLAYER_STATUS_ALIVE) && (player->muteki == 0))
player->status = PLAYER_STATUS_DEAD;
}
/* ショットとの当たり判定 */
if (p2->status != SHOT_STATUS_NON) {
signed short p2_w;
short hit_w;
if (((t = p->x + (hit_w = p->hit_sx)) >= (p2_w = *((short *) (&p2->lx))))
&& ((t -= (short) (hit_w << 1)) <= p2_w)
&& ((t = p->y + (hit_w = p->hit_sy)) >= (p2_w = *((short *) (&p2->ly))))
&& ((t -= (short) (hit_w << 1)) <= p2_w)) {
p->damage++; /* 敵キャラにダメージを与える */
/* ショットが当たった */
if (p->damage_mode == DAMAGE_THROUGH) {
/* ショットが貫通する敵の場合 */
p->shot_count = p2->shot_count;
if (p2->shot_count < 3)
p2->shot_count++;
} else {
/* ショットが刺さる敵の場合 */
if (p2->enemy == NULL) {
/* 既に刺さっていなければ */
if (p2->shot_count < 3)
p2->shot_count++;
p2->status = SHOT_STATUS_STICK;
p2->enemy = p;
p2->off_x = p2->x - p->x;
p2->off_y = p2->y - p->y;
p->shot = p2;
}
}
}
}
q = p;
p = p->next;
}
}
}
/* サービスルーチン */
enum {
MOVESEQ_ADD, MOVESEQ_FIX, MOVESEQ_SUB, MOVESEQ_END
};
/* 絶対座標 dx,dy に向かって移動する(初期化) */
void SubEnemyMoveToInit (ENEMY * p, signed short dest_x, signed short dest_y,
unsigned char speed, signed short count)
{
unsigned char angle;
signed short sx, sy;
sx = wabs (dest_x - p->x);
sy = wabs (dest_y - p->y);
angle = msearch (p->x, p->y, dest_x, dest_y); /* 移動方向 */
p->move_ax = xytable[speed][angle].x / 32;
p->move_ay = xytable[speed][angle].y / 32;
p->move_counter = p->move_count = count; /* 何回加速/減速するか */
/* 誤差を少なくするために大きい方で計算 */
/* 除数が絶対に 0 にならないようにするため +1 しています(小細工) */
if (sx > sy)
p->move_count2 = sx * 65536 / (abs (p->move_ax * count) + 1) - count;
else
p->move_count2 = sy * 65536 / (abs (p->move_ay * count) + 1) - count;
p->move_count3 = 0; /* 実際に加速/減速した回数 */
p->move_seq = MOVESEQ_ADD;
}
/* 座標 dx,dy に向かって移動する */
short SubEnemyMoveTo (ENEMY * p)
{
switch (p->move_seq) {
case MOVESEQ_ADD: /* 加速中 */
p->vx += p->move_ax;
p->vy += p->move_ay;
p->move_count3++;
if (p->move_counter-- <= 0) {
p->move_seq++; /* 加速したら次へ */
p->move_counter = p->move_count2;
}
break;
case MOVESEQ_FIX: /* 等速度運動中 */
if (p->move_counter-- <= 0) {
p->move_seq++; /* 加速したら次へ */
p->move_counter = p->move_count;
}
break;
case MOVESEQ_SUB: /* 減速中 */
p->vx -= p->move_ax;
p->vy -= p->move_ay;
p->move_count3--;
if (p->move_counter-- <= 0) /* ある程度減速したら次へ */
p->move_seq++;
break;
case MOVESEQ_END:
p->vx = p->vy = p->move_ax = p->move_ay = 0;
return (-1);
}
return (0);
}
/* 移動を中断する */
short SubEnemyMoveToAbort (ENEMY * p)
{
if (p->move_count3-- <= 0) {
p->vx = 0;
p->vy = 0;
return (-1);
}
p->vx -= p->move_ax;
p->vy -= p->move_ay;
return (0);
}